package main

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
)

var (
	DB_POOL     chan *sql.DB
	DB_HOST     = "127.0.0.1"
	DB_PORT     = "3306"
	DB_NAME     = "monitor"
	DB_USER     = "root"
	DB_PASSWORD = ""
	POOL_SIZE   = 20
	ROTATE      = true
	MAX_DAY     = 7
	LOG_FILE    = "logs/server.log"
)

//从数据库连接池中获取一个连接
func GetDBConn() *sql.DB {
	return <-DB_POOL
}

//初始化数据库连接池
func InitDB() {
	DB_POOL = make(chan *sql.DB, POOL_SIZE)
	go func() {
		for i := 0; i < POOL_SIZE; i++ {
			conn, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8", DB_USER, DB_PASSWORD,
				DB_HOST, DB_PORT, DB_NAME))
			if err != nil {
				panic(err)
			}
			_, err = conn.Query("select 1")
			if err != nil {
				log.Error("Cannot connect to the database host(%s) > %v", DB_HOST, err)
				return
			}
			DB_POOL <- conn
		}
		return
	}()
}

func NewDBConn() (*sql.DB, error) {
	conn, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8", DB_USER, DB_PASSWORD,
		DB_HOST, DB_PORT, DB_NAME))
	if nil != err {
		return nil, err
	}
	_, err = conn.Query("select 1")
	if nil != err {
		log.Error("Cannot connect to the database host(%s) > %v", DB_HOST, err)
		return nil, err
	}
	return conn, nil
}

func getHostByIP(ip string) *Host {
	conn := GetDBConn()
	defer func() {
		DB_POOL <- conn
	}()
	host := new(Host)
	err := conn.QueryRow("SELECT id,ip,last_check,update_interval FROM host_host WHERE ip=?", ip).
		Scan(&host.Id, &host.Ip, &host.LastCheck, &host.UpdateInterval)
	switch {
	case err == sql.ErrNoRows:
		log.Warn("no host with that ip <%s>", ip)
		return nil
	case nil != err:
		log.Warn("get host by ip error <%v>", err)
		return nil
	default:
		if s := getServiceById(host.Id); s != nil {
			host.Services = s
		}
		for _, s := range host.Services {
			if items := getItemByServiceId(s.Id); items != nil {
				s.Items = items
			}
		}
		return host
	}

}

func getServiceById(id int) []*Service {
	conn := GetDBConn()
	defer func() {
		DB_POOL <- conn
	}()
	rows, err := conn.Query(`SELECT id,name,plugin,args,update_interval FROM service_service WHERE id in
		(SELECT service_id FROM host_host_service WHERE host_id = ?)`, id)
	if nil != err {
		log.Warn("get service by host id error <%v>", err)
		return nil
	}
	defer rows.Close()
	s := []*Service{}
	for rows.Next() {
		service := new(Service)
		if err = rows.Scan(&service.Id, &service.Name, &service.Plugin, &service.Args, &service.UpdateInterval); nil != err {
			log.Warn("scan service by host id error <%v>", err)
			continue
		}
		s = append(s, service)
	}
	return s
}

func getItemByServiceId(id int) []*Item {
	conn := GetDBConn()
	defer func() {
		DB_POOL <- conn
	}()
	rows, err := conn.Query("SELECT `name`,`key` FROM monitor_items where id in "+
		"(SELECT `items_id` FROM service_service_items WHERE service_id =?)", id)
	if nil != err {
		log.Warn("get items by service id error <%b>", err)
		return nil
	}
	defer rows.Close()
	i := []*Item{}
	for rows.Next() {
		item := new(Item)
		if err = rows.Scan(&item.Name, &item.Key); nil != err {
			log.Warn("scan item by service id error <%v>", err)
			continue
		}
		i = append(i, item)
	}
	return i
}
func getClientVersion() *Client {
	conn := GetDBConn()
	defer func() {
		DB_POOL <- conn
	}()
	c := new(Client)
	err := conn.QueryRow("SELECT filename,version FROM host_agent WHERE distributed=0 order by timestramp desc limit 1").
		Scan(&c.Filename, &c.Version)
	switch {
	case err == sql.ErrNoRows:
		log.Warn("no version found <%v>", err)
		return nil
	case nil != err:
		log.Warn("get client version failed <%v>", err)
		return nil
	default:
		return c
	}
}
